<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>

<body>
    <script>
        //【1】模板字面量在 ES2015 规范中叫做 Template Literals，在规范文档更早的版本中叫 Template Strings;为表述方便也非正式地简称为 ES6 模板。
        // 【1-1】两个反撇号之间的常规字符串保持原样，如：
        function test() {
            `hello world` === "hello world" // --> true
            `hello "world"` === 'hello "world"' // --> true
            `hello 'world'` === "hello 'world'"; // --> true
        }
        // 【1-2】换行符也只是一个字符，因此模板字面量也自然就支持多行字符 
        console.log(`TODO LIST:
            * one
            * two
        `);
        // 【1-2】两个反撇号之间以 ${expression} 格式包含任意 JavaScript 表达式，该 expression 表达式的值会转换为字符串，与表达式前后的字符串拼接。
        // expression 展开为字符串时，使用的是 expression.toString() 函数。
        const name = "Alice";
        const a = 1
        const b = 2
        const fruits = ['apple', 'orange', 'banana']
        const now = new Date()
        console.log(`Hello ${name}`) // Hello Alice
        console.log(`1 + 2 = ${a + b}`) // 1 + 2 = 3
        console.log(`INFO: ${now}`) // INFO: Sun May 13 2018 22:28:26 GMT+0800 (中国标准时间)
        console.log(`Remember to bring: ${ fruits.join(', ') }.`) // Remember to bring: apple, orange, banana.
        console.log(`1 < 2 ${ 1 < 2 ? '✔︎' : '✘'}`); // 1 < 2 ✔︎
        //【1-3】正因为 expression 可以是 任意 JavaScript 表达式 ，而任意一个模板字符串本身也是一个表达式，所以模板中的 expression 可以嵌套另一个模板。
        const fruits1 = ['apple', 'orange', 'banana'];
        const quantities = [4, 5, 6]
        console.log(`I got ${fruits1.map((fruit, index) => `${quantities[index]} ${fruits1}s`).join(', ')}`);
        // I got 4 apple,orange,bananas, 5 apple,orange,bananas, 6 apple,orange,bananas
        //【2】与传统模板引擎对比
        //【2-1】第1，基本的字符串插值。
        // _.template 使用 <%= expression %> 作为模板插值分隔符，expression 的值将会按原始输出，与 ES6 模板相同。所以在这一个特性上，ES6 模板是完全胜任的。

        // lodash
        const compiled = _.template('hello <%= user %>!');
        console.log(compiled({ user: 'fred' }));// hello fred
        // ES6 模板
        const greeting = data => `hello ${data.user}`
        console.log(greeting({ user: 'fred' }));// hello fred

        //【2-2】第2，字符串转义输出
        const entityMap = {
            '&': '&amp;',
            '<': '&lt;',
            '>': '&gt;',
            '"': '&quot;',
            "'": '&#39;',
            '/': '&#x2F;',
            '`': '&#x60;',
            '=': '&#x3D;'
        }
        const escapeHTML = string => String(string).replace(/[&<>"'`=\/]/g, (s) => entityMap[s]);
        const greeting = data => `hello ${escapeHTML(data.user)}`;
        console.log(greeting({ user: ' <script>alert(0)'+'<script>'}));
        
        // hello &lt;script&gt;alert(0)&lt;&#x2F;script&gt; 
        // 【2-3】第3，模板内嵌 JavaScript 语句，也就是模板引擎支持通过在模板中执行 JavaScript语句，生成HTML。 // 说白了其原理与世界上最好的语言 php 的 idea 是一样的。在 lodash 模板中，使用
        // <% statement %> 就可以执行 JS 语句，一个最典型的使用场景是使用 for 循环在模版中迭代数组内容。

        // 但 ES6 模板中的占位符 ${} 只支持插入表达式，所以要在其中直接执行 for 循环这样的 JavaScript 语句是不行的。但是没关系，同样的输出结果我们用一些简单的技巧一样可以搞定，
        // 例如对数组的处理，我们只要善用数组的 map、 reduce、filter ，令表达式的结果符合我们需要即可。

        const listRenderer = data => `<ul>${data.users.map(user => `<li>${user}</li>`).join('')}</ul>`
        console.log(listRenderer({ users: ['fred', 'barney']}))
        // <ul><li>fred</li><li>barney</li></ul>
    </script>
</body>

</html>